﻿//-------------
// <copyright file="UserController.cs" company="Uncas">
//     Copyright (c) Ole Lynge Sørensen. All rights reserved.
// </copyright>
//-------------

namespace Uncas.Katas.SimpleMembership.Web.Controllers
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using Uncas.Katas.SimpleMembership.Domain;
    using Uncas.Katas.SimpleMembership.Web.Mappers;
    using Uncas.Katas.SimpleMembership.Web.ViewModels;

    /// <summary>
    /// Controller for user pages.
    /// </summary>
    public class UserController : Controller
    {
        /// <summary>
        /// The user repository.
        /// </summary>
        private readonly IUserRepository repository;

        /// <summary>
        /// Initializes a new instance of the <see cref="UserController"/> class.
        /// </summary>
        /// <param name="repository">The repository.</param>
        public UserController(IUserRepository repository)
        {
            this.repository = repository;
        }

        /// <summary>
        /// Controls changing the password.
        /// </summary>
        /// <param name="userName">The user name.</param>
        /// <param name="password">The password.</param>
        /// <returns>Redirect to details about the user.</returns>
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult ChangePassword(
            string userName,
            string password)
        {
            this.repository.ChangePassword(userName, password);
            return RedirectToAction("Details", new { userName = userName });
        }

        /// <summary>
        /// Controls deletion of the specified user.
        /// </summary>
        /// <param name="userName">The user name.</param>
        /// <returns>Redirect to index.</returns>
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Delete(
            string userName)
        {
            this.repository.DeleteUser(userName);
            return RedirectToAction("Index");
        }

        /// <summary>
        /// Controls getting details about the specified user.
        /// </summary>
        /// <param name="userName">The user name.</param>
        /// <returns>View with the details about the user.</returns>
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Details(string userName)
        {
            var user = this.repository.GetUser(userName);
            if (user == null)
            {
                return RedirectToAction("Index");
            }

            var rolesForUser = this.repository.GetRolesForUser(userName);
            var roles = new MultiSelectList(
                this.repository.GetAllRoleNames(),
                rolesForUser);
            var result = new UserDetailsViewModel
            {
                UserName = userName,
                Email = user.Email,
                IsApproved = user.IsApproved,
                Roles = roles
            };
            return View(result);
        }

        /// <summary>
        /// Controls updating details about the specified user.
        /// </summary>
        /// <param name="userName">The user name.</param>
        /// <param name="email">The email.</param>
        /// <param name="isApproved">if set to <c>true</c> [is approved].</param>
        /// <param name="roles">The roles.</param>
        /// <returns>Redirect to the index.</returns>
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Details(
            string userName,
            string email,
            bool isApproved,
            IEnumerable<string> roles)
        {
            this.repository.UpdateUser(userName, email, isApproved);

            foreach (string roleName in this.repository.GetAllRoleNames())
            {
                if (this.repository.IsUserInRole(userName, roleName) &&
                    !DoesRolesContain(roles, roleName))
                {
                    this.repository.RemoveUserFromRole(userName, roleName);
                }

                if (!this.repository.IsUserInRole(userName, roleName) &&
                    DoesRolesContain(roles, roleName))
                {
                    this.repository.AddUserToRole(userName, roleName);
                }
            }

            return RedirectToAction("Index");
        }

        /// <summary>
        /// Controls a list of users.
        /// </summary>
        /// <returns>The view with the list of users.</returns>
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Index()
        {
            var users = this.repository.GetUsers();
            var result = users.Select(u => UserMapper.MapUserToViewModel(u));
            return View(result);
        }

        /// <summary>
        /// Constrols creation of a new user.
        /// </summary>
        /// <param name="userName">The user name.</param>
        /// <param name="password">The password.</param>
        /// <param name="email">The email.</param>
        /// <returns>Redirect to the details of the newly created user.</returns>
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Index(
            string userName,
            string password,
            string email)
        {
            this.repository.CreateUser(userName, password, email);
            return RedirectToAction("Details", new { userName = userName });
        }

        /// <summary>
        /// Checks if the list of roles contains the specified role.
        /// </summary>
        /// <param name="roles">The roles.</param>
        /// <param name="roleName">Name of the role.</param>
        /// <returns>
        /// True if the roles contains the given role name, otherwise false.
        /// </returns>
        private static bool DoesRolesContain(
            IEnumerable<string> roles,
            string roleName)
        {
            return roles != null && roles.Contains(roleName);
        }
    }
}